package net.chenlin.dp.modules.socket;

import java.io.*;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author Yangsm
 * @ClassName: KeepClient
 * @Description: TODO
 * @date 2022年11月16日 21:31
 */
public class KeepClient {

    /**
     * 处理服务端发回的对象，可实现该接口。
     */
    public static interface ObjectAction {
        void doAction(Object obj, KeepClient client);
    }

    public static final class DefaultObjectAction implements KeepClient.ObjectAction {
        @Override
        public void doAction(Object obj, KeepClient client) {
            System.out.println(" ================ ");
            //System.out.println("客户端Client接受并处理：\t" + obj.toString());
        }
    }

    private String serverIp;
    private int port;
    private Socket socket;
    private boolean running = false; //连接状态

    private long lastSendTime; //最后一次发送数据的时间

    //用于保存接收消息对象类型及该类型消息处理的对象
    private ConcurrentHashMap<Class, KeepClient.ObjectAction> actionMapping = new ConcurrentHashMap<Class, KeepClient.ObjectAction>();

    public KeepClient(String serverIp, int port) {
        this.serverIp = serverIp;
        this.port = port;
    }

    public void start() throws UnknownHostException, IOException {
        if (running) {
            return;
        }
        socket = new Socket(serverIp, port);
        System.out.println("本地端口：" + socket.getLocalPort());
        lastSendTime = System.currentTimeMillis();
        System.out.println("上次发送的时间"+lastSendTime);
        running = true;
        //保持长连接的线程，每隔2秒项服务器发一个一个保持连接的心跳消息
        new Thread(new KeepClient.KeepAliveWatchDog()).start();

        //接受消息的线程，处理消息
        new Thread(new KeepClient.ReceiveWatchDog()).start();
        System.out.println("Client端启动成功");
    }

    public void stop() {
        if (running) {
            running = false;
        }
    }

    /**
     * 添加接收对象的处理对象。
     *
     * @param cls    待处理的对象，其所属的类。
     * @param action 处理过程对象。
     */
    public void addActionMap(Class<Object> cls, KeepClient.ObjectAction action) {
        actionMapping.put(cls, action);
    }

    public void sendObject(String str) throws IOException {
        OutputStream os = socket.getOutputStream();
        os.write(str.getBytes());
        System.out.println("客户端Client发送的消息：\t" + str);
    }

    // 主动发起通话，发给服务端消息
    class KeepAliveWatchDog implements Runnable {

        long checkDelay = 5000;

        // 间隔五秒发送一次
        long keepAliveDelay = 5000;

        @Override
        public synchronized void run() {
            while (running) {
                if (System.currentTimeMillis() - lastSendTime > keepAliveDelay) {
                    try {
                        //String mes = "心跳保持中#$!";
                        String mes = "{2387694,20221107110738,REG}";
                        KeepClient.this.sendObject(mes);
                        lastSendTime = System.currentTimeMillis();
                    } catch (IOException e) {
                        e.printStackTrace();
                        KeepClient.this.stop();
                    }
                } else {
                    try {
                        //当间隔时间没到，延迟10mills
                        Thread.sleep(checkDelay);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        KeepClient.this.stop();
                    }
                }
            }
        }
    }

    // 收到服务端的消息并回复
    class ReceiveWatchDog implements Runnable {
        @Override
        public void run() {
            while (running) {
                try {
                    InputStream in = socket.getInputStream();
                    // 一次读取多个字节
                    if (in.available() > 0) {

                        // 客户端收到来自服务端回的消息

                        byte[] by = new byte[1024];
                        int len = in.read(by);
                        String data = new String(by,0,len);
                        System.out.println("客户端接收到服务端的消息是：== "+data);
                        if(!data.equals("心跳保持中")){
                            // 客户端回给服务端的消息

                            OutputStream os = socket.getOutputStream();
                            //发送数据
                            String str = "Hi,TCP-杨士民，我收到服务端你回的消息了，哈哈，我也是还在线的哦!";
                            os.write(str.getBytes());
                        }


                        //socket.close();

                    } else {
                        Thread.sleep(10);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    KeepClient.this.stop();
                }
            }
        }
    }

}
